package com.course.redis.service;

import cn.hutool.core.util.StrUtil;
import com.course.common.enums.RedisKeyConstant;
import com.course.common.model.vo.ShortUserInfo;
import com.course.common.model.vo.SignInUserInfo;
import com.course.common.util.CopyUtil;
import com.course.redis.mapper.UserPointsMapper;
import com.course.redis.model.pojo.UserPoints;
import com.course.redis.model.vo.UserPointsRankVo;
import com.google.common.collect.Lists;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @PROJECT_NAME: course
 * @DESCRIPTION: 用户积分Service层
 * @Author: 涂玄武
 * @DATE: 2021/7/9 14:19
 */
@Service
public class UserPointsService {

    @Resource
    private UserPointsMapper userPointsMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UserService userService;

    /**
     * 添加积分
     *
     * @param userId 用户ID
     * @param points 积分
     * @param types  积分类型：0-签到，1-关注好友，2-添加评论，3-点赞商户
     */
    public void addPoints(Integer userId, Integer points, Integer types) {
        //插入数据库
        UserPoints userPoints = new UserPoints();
        userPoints.setFkUserId(userId);
        userPoints.setPoints(points);
        userPoints.setTypes(types);
        userPointsMapper.save(userPoints);
    }

    /**
     * 获取前20排行榜
     */
    private static final int TOPN = 20;

    /**
     * 查询前 20 积分排行榜，并显示个人排名 -- Redis
     *
     * @param signInUserInfo
     * @return
     */
    public List<UserPointsRankVo> findUserPointRankFromRedis(SignInUserInfo signInUserInfo) {
        //统计积分排行榜
        Set<ZSetOperations.TypedTuple<Integer>> rangeWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(
                RedisKeyConstant.user_points.getKey(), 0, 10
        );
        if (CollectionUtils.isEmpty(rangeWithScores)) {
            return Lists.newArrayList();
        }
        //初始化用户ID集合
        List<Integer> rankUserIds = Lists.newArrayList();
        //根据key：用户ID value：积分信息 构建一个Map
        Map<Integer, UserPointsRankVo> ranksMap = new LinkedHashMap<>();
        //初始化排名
        int rank = 1;
        //循环处理排行榜，添加排名信息
        for (ZSetOperations.TypedTuple<Integer> rangeWithScore : rangeWithScores) {
            //用户ID
            Integer rUserId = rangeWithScore.getValue();
            //积分
            int rPoints = rangeWithScore.getScore().intValue();
            //将用户ID添加至用户ID集合
            rankUserIds.add(rUserId);
            UserPointsRankVo userPointsRankVo = new UserPointsRankVo();
            userPointsRankVo.setId(rUserId);
            userPointsRankVo.setRanks(rank);
            userPointsRankVo.setTotal(rPoints);
            //将VO对象添加至Map中
            ranksMap.put(rUserId,userPointsRankVo);
            //排名+1
            rank++;
        }

        //获取users用户信息
        List<ShortUserInfo> byIds = userService.findByIds(StrUtil.join(",", rankUserIds));
        for (ShortUserInfo userInfo : byIds){
            UserPointsRankVo rankVo = ranksMap.get(userInfo.getId());
            rankVo.setNickname(userInfo.getNickname());
            rankVo.setAvatarUrl(userInfo.getAvatarUrl());
        }

        //判断个人是否在ranks中，如果在，添加标记直接返回
        if (ranksMap.containsKey(signInUserInfo.getId())) {
            UserPointsRankVo myRank = ranksMap.get(signInUserInfo.getId());
            myRank.setIsMe(1);
            return Lists.newArrayList(ranksMap.values());
        }

        //如果不在ranks中，获取个人排名追加在后面
        //获取排名
        Long myRank = redisTemplate.opsForZSet().reverseRank(
                RedisKeyConstant.user_points.getKey(), signInUserInfo.getId());
        if (myRank != null){
            UserPointsRankVo me = CopyUtil.copy(signInUserInfo, UserPointsRankVo.class);
            me.setRanks(myRank.intValue());
            me.setIsMe(1);
            //获取积分
            Double points = redisTemplate.opsForZSet().score(
                    RedisKeyConstant.user_points.getKey(), signInUserInfo.getId());
            me.setTotal(points.intValue());
            ranksMap.put(signInUserInfo.getId(),me);
        }
        return Lists.newArrayList(ranksMap.values());
    }

    /**
     * 查询前 20 积分排行榜，并显示个人排名 -- MySQL
     *
     * @param userId
     * @return
     */
    public List<UserPointsRankVo> findUserPointRank(Integer userId) {
        //统计积分排行榜
        List<UserPointsRankVo> ranks = userPointsMapper.findTopN(TOPN);
        if (CollectionUtils.isEmpty(ranks)) {
            return Lists.newArrayList();
        }
        //根据key：用户ID value：积分信息 构建一个Map
        Map<Integer, UserPointsRankVo> ranksMap = new LinkedHashMap<>();
        for (int i = 0; i < ranks.size(); i++) {
            ranksMap.put(ranks.get(i).getId(), ranksMap.get(i));
        }
        //判断个人是否在ranks中，如果在，添加标记直接返回
        if (ranksMap.containsKey(userId)) {
            UserPointsRankVo myRank = ranksMap.get(userId);
            myRank.setIsMe(1);
            return Lists.newArrayList(ranksMap.values());
        }
        //如果不在ranks中，获取个人排名追加在后面
        UserPointsRankVo myRank = userPointsMapper.findUserrRank(userId);
        myRank.setIsMe(1);
        ranks.add(myRank);
        return ranks;
    }


}
